import json
from datetime import datetime

from decimal import Decimal

from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection

from apps.ausers.models import Address
from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from utils.response_code import RETCODE
import time
# 4.展示订单
class OrderListView(LoginRequiredMixin, View):
    def get(self, request, page_num):
        # 查询当前用户的所有订单
        order_list = OrderInfo.objects.filter(user_id=request.user.id).order_by('-create_time')

        # 分页
        paginator = Paginator(order_list, 3)
        # 123
        total_page = paginator.num_pages

        page = paginator.page(page_num)


        # 转换成前端需要的格式
        page_list = []
        for order in page:
            detail_list = []
            for detail in order.skus.all():
                detail_list.append({
                    'default_image_url': detail.sku.default_image.url,
                    'name': detail.sku.name,
                    'price': detail.price,
                    'count': detail.count,
                    'total': detail.price * detail.count
                })

            page_list.append({
                'create_time': order.create_time,
                'order_id': order.order_id,
                'detail_list': detail_list,
                'total_amount': order.total_amount,
                'freight': order.freight,
                'status': order.status
            })

        context = {
            'page': page_list,
            'page_num': page_num,
            'page_total': paginator.num_pages,
            'total_page': total_page,  # 总页数

        }

        return render(request, 'user_center_order.html', context)

# 订单成功页面显示
class OrderSuccessView(View):
    def get(self, request):
        context = {
            'payment_amount': request.GET.get('payment_amount'),
            'order_id': request.GET.get('order_id'),
            'pay_method': request.GET.get('pay_method'),
        }
        return render(request, 'order_success.html', context)

# 提交订单
class OrderCommitView(LoginRequiredMixin,View):
    def post(self, request):
        #   1. 接收解析解析参数 address_id payt_method
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        #   2. 校验 1.判空 2.地址是否有 3. pay-method是否
        if not all([address_id, pay_method]):
            return http.HttpResponseBadRequest('参数不齐!')
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.HttpResponseBadRequest('收货地址不存在!')

        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseBadRequest('支付方式不支持!')

        user = request.user
        # 3. 生成唯一 时间订单号
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + ("%09d" % user.id)

        from django.db import transaction
        with transaction.atomic():
            save_id = transaction.savepoint()

            try:
                # 4. 创建orderInfo这个数据 order,user,address,pay_method, freight: Deciaml(10.0)
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    pay_method=pay_method,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.0'),
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                    if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY']
                    else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                #   5. 获取购物车redis数据 ; 商品必须选中状态
                redis_client = get_redis_connection('carts')
                client_data = redis_client.hgetall(user.id)
                carts_selected_dict = {}
                for data in client_data.items():
                    sku_id = int(data[0].decode())
                    sku_dict = json.loads(data[1].decode())
                    # 是否选中
                    if sku_dict['selected']:
                        carts_selected_dict[sku_id] = sku_dict

                # 6. 根据购物车 sku_ids 获取 skus商品 SKU
                sku_ids = carts_selected_dict.keys()
                # skus = SKU.objects.filter(id__in=sku_ids)
                for sku_id in sku_ids:
                    while True:
                        sku = SKU.objects.get(id=sku_id)
                        # 获取老的库存和销量
                        origin_stock =sku.stock
                        origin_sales = sku.sales
                        #   7. 判断sku的库存量  购买的个数count > 库存量sku.stock: 购买失败
                        sku_count = carts_selected_dict[sku.id]['count']
                        if sku_count > sku.stock:
                            # 事务回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # 8. sku 库存量减少, 销量增加
                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # sku.save()
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        result=SKU.objects.filter(id=sku.id,stock=origin_stock).update(stock=new_stock,sales=new_sales)
                        # 如果库存足够的情况下 , 下单失败 ,应该是给多次机会 直到下单成功
                        if result == 0:
                            continue
                        #   9. spu 销量增加
                        sku.spu.sales += sku_count
                        sku.spu.save()

                        # 11. 订单商品表 创建 order,sku有关系属性
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            price=sku.price,
                            count=sku_count
                        )
                        # 10. 计算该sku的总价格, 总个数;
                        order.total_count += sku_count
                        order.total_amount += (sku_count * sku.price)
                        # 跳出死循环
                        break
                # 12. 累加运费, orderInfo.save()
                order.total_amount += order.freight
                order.save()
                #事务提交
                transaction.savepoint_commit(save_id)
            except Exception as e:
                #暴力回滚
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '订单失败！'})

        # 13. 清空选中购物车数据
        redis_client.hdel(user.id, *carts_selected_dict)

        # 14. 返回前端的响应结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})

# 首页
class OrderSettlementView(LoginRequiredMixin,View):
    def get(self, request):

        # 1.地址
        try:
            addresses = Address.objects.filter(user=request.user,is_deleted=False)
        except Exception as e:
            addresses = None

        # 2. 支付方式
        # 3. redis购物车里面选中的 商品
        redis_client = get_redis_connection('carts')
        client_data = redis_client.hgetall(request.user.id)
        carts_dict = {}
        for data in client_data.items():
            sku_id = int(data[0].decode())
            sku_dict = json.loads(data[1].decode())

            if sku_dict['selected']:
                carts_dict[sku_id] = sku_dict

        total_count = 0
        total_amount = Decimal(0.00)

        skus = SKU.objects.filter(id__in=carts_dict.keys())
        for sku in skus:
            sku.count = carts_dict[sku.id].get('count')
            sku.amount = sku.price * sku.count

            total_count += sku.count
            total_amount += sku.amount

        freight = Decimal('10.00')
        total_price_all = total_amount + freight


        # 4. 组合前端需要的数据格式
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_price_all,
            'default_address_id': request.user.default_address_id
        }
        return render(request, 'place_order.html', context)
